home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-04-10 | 9.1 KB | 268 lines | [TEXT/MPS ] |
- ;-------------------------------------------------------------------------
- ;
- ; MakeRgn.a
- ;
- ; Written by Ted Cohn, March 1987.
- ; Copyright 1988 By Ted Cohn.
- ;
- ; The function MakeRgn converts a bitmap image into a Quickdraw region.
- ; The image bits which are 1 are logically included in the resultant
- ; region whereas 0 bits are not included. There are no special
- ; conditions required of the bitmap - it may be arbitrarily complex.
- ; An empty bitmap will simply yield an empty region. The rgnBBox of
- ; the resultant region may be smaller than the initial bitmap bounds
- ; if the image does not use the full extent of the bitmap. The rgnBBox
- ; will be the smallest rectangle enclosing the resultant region.
- ;
- ; Algorithm Summary:
- ;
- ; The idea behind the conversion is simple. The key is in finding
- ; the inversion points of the picture which define the region.
- ; A source bitmap is first XOR'd with its right-shifted copy. The resultant
- ; bitmap is then XOR'd with its down-shifted copy. This produces a set of
- ; inversion points which define the region boundary. The next step is to take
- ; these points within the final bitmap and convert them to Quickdraw region
- ; format.
- ;
- ; FUNCTION MakeRgn(image: BitMap): RgnHandle;
- ;
- ; Modification History:
- ;
- ; 25-Mar-87 New Today.
- ; 26-Mar-87 Ironed out bugs.
- ; 30-Mar-87 Changed to Pascal function.
- ; 28-Mar-88 Optimized and reduced code.
- ;-------------------------------------------------------------------------
-
- MACHINE MC68000
-
- INCLUDE 'Traps.a'
- INCLUDE 'QuickEqu.a'
-
- ENDMARK EQU $7FFF ; endmark [word].
-
- ; MakeRgn's stack frame:
-
- MRFrame RECORD {A6Link},DECREMENT
- dstRgn DS.L 1 ; output region [RgnHandle].
- srcMap DS.L 1 ; source bitmap [Ptr].
- Return DS.L 1 ; return address [Ptr].
- A6Link DS.L 1 ; old A6 value [long].
- srcRect DS.B 8 ; temp [Rect].
- dstRect DS.B 8 ; temp [Rect].
- rgnMap DS.B 14 ; temp bitmap [BitMap].
- VarSize EQU * ; size of local variables.
- ENDR
-
- MakeRgn PROC EXPORT
- WITH MRFrame
- LINK A6,#VarSize ; create local stack frame.
- MOVEM.L A1-A3/D0-D7,-(SP) ; save working registers.
- MOVE.L srcMap(A6),A3 ; load ptr to source bitmap.
- MOVEQ #0,D0 ; clear for multiplying.
- MOVEQ #0,D4 ; use D4 for faster clears.
- MOVE.W rowBytes(A3),D7 ; load srcMap rowBytes.
- ;
- ; Find number of lines in the source bitmap. The rgnMap will have
- ; the same number of lines plus one and two more rowbytes.
- ;
- MOVE.W bounds+bottom(A3),D0 ; load srcMap bottom.
- SUB.W bounds+top(A3),D0 ; height = bottom-top.
- ADDQ.W #1,D0 ; height++.
- ADDQ.W #2,D7 ; rowBytes += 2.
- ;
- ; Fill in rgnMap rowBytes and baseAddr fields. Allocate memory
- ; for the temporary rgnMap image buffer.
- ;
- MOVE.W D7,rgnMap+rowBytes(A6) ; store new rowBytes.
- MULU D7,D0 ; calculate bitmap size.
- _NewPtr ,clear ; create rgnMap image buffer.
- MOVE.L A0,rgnMap+baseAddr(A6) ; store start of buffer.
- ;
- ; The rgnMap's bounds will be one pixel larger to the right and bottom.
- ;
- MOVE.L bounds+topLeft(A3),D0 ; get original bitmap bounds.
- MOVE.L bounds+botRight(A3),D1
- ADDQ.W #1,D1 ; right++.
- MOVE.L D0,rgnMap+bounds+topLeft(A6)
- MOVE.L D1,rgnMap+bounds+botRight(A6)
- ADDQ.W #1,rgnMap+bounds+bottom(A6)
- ;
- ; Now make right-shifted copy in rgnMap.
- ;
- ADDQ.W #1,D0 ; left++.
- MOVE.L D0,dstRect+topLeft(A6) ; dstRect is right-shifted one.
- MOVE.L D1,dstRect+botRight(A6)
- MOVE.L A3,-(SP) ; srcBits = srcMap.
- PEA rgnMap(A6) ; dstBits = rgnMap.
- PEA bounds(A3) ; srcRect = srcMap.bounds.
- PEA dstRect(A6) ; dstRect.
- MOVE.W D4,-(SP) ; srcCopy mode.
- MOVE.L D4,-(SP) ; no maskRgn.
- _CopyBits
- ;
- ; XOR srcMap with right-shifted copy rgnMap and store in rgnMap.
- ;
- MOVE.L A3,-(SP) ; srcBits = srcMap.
- PEA rgnMap(A6) ; dstBits = rgnMap.
- PEA bounds(A3) ; srcRect = srcMap.bounds.
- PEA bounds(A3) ; dstRect = srcMap.bounds.
- MOVE.W #srcXor,-(SP) ; srcXor mode.
- MOVE.L D4,-(SP) ; no maskRgn.
- _CopyBits
- ;
- ; XOR rgnMap with down-shifted copy of rgnMap.
- ;
- MOVE.L rgnMap+bounds+topLeft(A6),srcRect+topLeft(A6)
- MOVE.L rgnMap+bounds+botRight(A6),srcRect+botRight(A6)
- MOVE.L srcRect+topLeft(A6),dstRect+topLeft(A6)
- MOVE.L srcRect+botRight(A6),dstRect+botRight(A6)
- SUBQ.W #1,srcRect+bottom(A6)
- ADDQ.W #1,dstRect+top(A6)
- PEA rgnMap(A6) ; srcBits = rgnMap.
- PEA rgnMap(A6) ; dstBits = rgnMap.
- PEA srcRect(A6) ; srcRect is top overlap.
- PEA dstRect(A6) ; dstRect is bottom overlap.
- MOVE.W #srcXor,-(SP) ; srcCopy mode.
- MOVE.L D4,-(SP) ; no maskRgn.
- _CopyBits
- ;
- ; We've exposed the inversion points of the picture. Time to
- ; count the number of rows and black pixels in the rgnMap to determine
- ; the size of the RgnHandle we will soon fill in.
- ;
- MOVE.L rgnMap+baseAddr(A6),A0 ; start at topLeft of bitmap.
- LSR.W #1,D7 ; rowWords = rowBytes/2.
- SUBQ.W #1,D7 ; loop rowWords times.
- MOVE.W rgnMap+bounds+top(A6),D1 ; current Y coordinate.
- MOVE.W rgnMap+bounds+bottom(A6),A1 ; Y coord. for end test.
- MOVEQ #0,D5 ; row count = 0.
- Count
- MOVE.W D7,D6 ; x loop on rowWords.
- MOVEQ #0,D3 ; clear line flag.
- @0
- MOVE.W (A0)+,D0 ; load next rgnMap word.
- BEQ.S @2 ; skip blank words.
- TST.B D3 ; line flag already set?
- BNE.S @1 ; yes --> skip.
- ST D3 ; no --> set line flag.
- ADDQ.W #1,D5 ; row count++.
- @1
- ADDQ.W #1,D4 ; add number of bits
- MOVE.W D0,D2 ; in rgnMap word to
- SUBQ.W #1,D2 ; total bit count.
- AND.W D2,D0
- BNE.S @1
- @2
- DBRA D6,@0 ; loop if more words to read.
- ADDQ.W #1,D1 ; y++.
- CMP.W D1,A1 ; y <= bottom?
- BGT.S Count ; yes --> loop.
- ;
- ; Determine size of new RgnHandle.
- ;
- TST.W D5 ; was the rgnMap empty?
- BNE.S BuildRgn ; no --> skip.
- SUBQ.W #4,SP ; yes --> get new empty region.
- _NewRgn
- MOVE.L (SP)+,dstRgn(A6) ; stuff result.
- BRA Done ; exit.
- BuildRgn
- ;
- ; Calculate number of bytes to allocate for output region handle.
- ;
- MOVEQ #12,D0 ; (12 for header & end-of-rgn mark.)
- ADD.W D5,D5 ; (4*number of lines in map for
- ADD.W D5,D5 ; each Y coordinate and
- ADD.W D5,D0 ; end mark.)
- ADD.W D4,D4 ; (2*number of inversion
- ADD.W D4,D0 ; points in the entire map.)
- MOVE.W D0,D4 ; remember the region size.
- _NewHandle ,clear ; allocate a cleared RgnHandle.
- MOVE.L A0,dstRgn(A6) ; store handle in result.
- ;
- ; Translate rgnMap (containing inversion points) into Quickdraw Region
- ; format. We do not need to lock the block because we will be making no
- ; trap calls (which might rearrange the heap). DstRect will be used to
- ; help us find the smallest enclosing rectangle for the region.
- ;
- MOVE.L (A0),A0 ; point to rgn data.
- MOVE.W D4,rgnSize(A0) ; store region size.
- MOVE.L A0,A2 ; save ptr for the end.
- LEA rgnData(A0),A0 ; offset ptr to rgnData.
- MOVE.L rgnMap+baseAddr(A6),A1 ; point to topLeft of bitmap.
- MOVE.W rgnMap+bounds+top(A6),D1 ; y = top.
- MOVE.W D1,dstRect+bottom(A6) ; initialize dstRect...
- MOVE.W rgnMap+bounds+left(A6),dstRect+right(A6)
- MOVE.L rgnMap+bounds+botRight(A6),dstRect+topLeft(A6)
- ;
- ; The line flag tells us if the scanline is not completely blank after
- ; reading the whole line. If not blank, then we add an end-of-line mark.
- ;
- Translate
- MOVE.W D7,D6 ; load word count.
- MOVEQ #0,D5 ; clear line flag.
- MOVE.W rgnMap+bounds+left(A6),D3 ; x = left edge.
- @0
- MOVE.W (A1)+,D0 ; load srcMap word.
- BNE.S @NotEmpty ; only process non-zero words.
- ADD.W #16,D3 ; skip zero words for speed.
- BRA.S @4
- @NotEmpty
- TST.B D5 ; is line flag set?
- BNE.S @1 ; yes --> skip.
- ST D5 ; no --> set line flag.
- MOVE.W D1,(A0)+ ; store y coord. in structure.
- CMP.W dstRect+top(A6),D1 ; now find the topmost
- BGE.S @MaxBottom ; row of the region.
- MOVE.W D1,dstRect+top(A6) ; top = min(top,y).
- @MaxBottom
- CMP.W dstRect+bottom(A6),D1 ; now find the bottommost
- BLE.S @1 ; row of the region.
- MOVE.W D1,dstRect+bottom(A6) ; bottom = max(bottom,y).
- @1
- OR.B #$10,CCR ; set the X flag.
- ADDX.W D0,D0 ; shift in end-bit-marker.
- @2
- BCC.S @3 ; branch if MSB clear.
- MOVE.W D3,(A0)+ ; store x coord. in structure.
- CMP.W dstRect+left(A6),D3 ; now find the leftmost
- BGE.S @MaxRight ; edge of the region.
- MOVE.W D3,dstRect+left(A6) ; left = min(left,x).
- @MaxRight
- CMP.W dstRect+right(A6),D3 ; now find the rightmost
- BLE.S @3 ; edge of the region.
- MOVE.W D3,dstRect+right(A6) ; right = max(right,x).
- @3
- ADDQ.W #1,D3 ; increment the x coordinate.
- ADD.W D0,D0 ; shift msb into carry.
- BNE.S @2 ; repeat if more one-bits.
- @4
- DBRA D6,@0 ; loop on rowWords-1.
- TST.B D5 ; empty line?
- BEQ.S @5 ; yes -->
- MOVE.W #ENDMARK,(A0)+ ; no, store end-of-line mark.
- @5
- ADDQ.W #1,D1 ; increment the y coordinate.
- CMP.W rgnMap+bounds+bottom(A6),D1 ; loop if y <= bottom of rgnMap.
- BLT.S Translate
- ;
- ; We are finished entering information into the rgnData field.
- ; Mark the end of the region and fill in the rgnBBox field.
- ;
- MOVE.W #ENDMARK,(A0) ; store end-of-region mark.
- MOVE.L dstRect+topLeft(A6),rgnBBox+topLeft(A2)
- MOVE.L dstRect+botRight(A6),rgnBBox+botRight(A2)
- Done
- MOVE.L rgnMap+baseAddr(A6),A0 ; deallocate temporary bitmap.
- _DisposPtr
-
- MOVEM.L (SP)+,A1-A3/D0-D7 ; restore working registers.
- UNLK A6 ; unlink the stack frame.
- MOVE.L (SP)+,A0 ; load return address.
- ADDQ.W #4,SP ; pop parameter.
- JMP (A0) ; return.
- ENDWITH
- ENDPROC
- END
-